生成随机数的能力在某些类型的程序中非常有用,特别是在游戏、统计建模程序和需要对随机事件建模的科学模拟中。以游戏为例——如果没有随机事件,怪物总是以同样的方式攻击你,你总是会找到同样的宝藏,地牢的布局永远不会改变,等等……这不会成为一个很好的游戏。
1 自定义伪随机数
基本思路是通过设置种子数、组合乘法、加法和迭代,再通过循环求余便可以得出一些简单的随机数。
#include <iostream>
unsigned int PRNG()
{
// our initial starting seed is 5323
static unsigned int seed = 5323;
// Take the current seed and generate a new value from it
// Due to our use of large constants and overflow, it would be
// hard for someone to casually predict what the next number is
// going to be from the previous one.
seed = 8253729 * seed + 2396403;
// Take the seed and return a value between 0 and 32767
return seed % 32768;
}
int main()
{
// Print 20 random numbers
for (int count=1; count <= 20; ++count)
{
std::cout << PRNG()*100/32768 << "\t";
// If we've printed 5 numbers, start a new row
if (count % 5 == 0)
std::cout << "\n";
}
system("pause");
return 0;
}
/*
23 4 67 22 77
44 30 45 99 0
59 85 87 74 56
42 42 65 20 17
*/
2 标准库中的随机数函数
标准库中有两个函数用于产生随机数:
srand(int); //设置起始种子值
rand();// 产生随机数
#include <iostream>
#include <stdlib.h> // for std::rand() and std::srand()
int main()
{
srand(5323); // set initial seed value to 5323
// Print 20 random numbers
for (int count=1; count <= 20; ++count)
{
std::cout << 100 + rand()/100 << "\t";
// If we've printed 5 numbers, start a new row
if (count % 5 == 0)
std::cout << "\n";
}
system("pause");
return 0;
}
/*
274 185 294 113 369
177 381 252 278 169
149 104 226 387 307
418 337 391 258 399
*/
3 选择随机性更强的随机种子(时间)
头文件
#include <iostream>
#include <cstdlib> // for std::rand() and std::srand()
#include <ctime> // for std::time()
int main()
{
srand(static_cast
// set initial seed value to system clock
for (int count=1; count <= 20; ++count)
{
std::cout << rand()%100 << "\t";
// If we've printed 5 numbers, start a new row
if (count % 5 == 0)
std::cout << "\n";
}
system("pause");
return 0;
}
/*
70 22 48 60 15
87 41 20 56 0
51 7 68 37 4
98 62 96 80 18
*/
4 在两个任意值之间生成随机数
#include <iostream>
#include <time.h>
using namespace std;
// Generate a random number between min and max (inclusive)
// Assumes srand() has already been called
// Assumes max - min <= RAND_MAX
int getRandomNumber(int min, int max)
{
double fraction = 1.0 / (RAND_MAX + 1.0);
// evenly distribute the random number across our range
return min + static_cast
}
int main()
{
srand(time(0));
for(int i=1; i<21; i++)
{
cout<<getRandomNumber(100,200)<<" ";
if(i%5==0)
cout<<endl;
}
system("pause");
return 0;
}
/*
184 172 153 106 197
111 156 167 200 169
124 105 167 185 113
171 144 104 176 192
*/
为什么我们在上面的函数中使用除法而不是模。简而言之,模方法倾向于偏向于低数值。
让我们考虑一下如果上面的函数是这样的话会发生什么:
min+(std::rand()%(max min+1));
看起来很相似,对吧让我们来看看哪里出了问题。为了简化这个例子,假设rand()总是返回一个介于0和9(包括0和9)之间的随机数,对于我们的示例,我们将选择min=0,max=6因此,max-min+1是7。
现在让我们计算所有可能的结果:
0 + (0 % 7) = 0
0 + (1 % 7) = 1
0 + (2 % 7) = 2
0 + (3 % 7) = 3
0 + (4 % 7) = 4
0 + (5 % 7) = 5
0 + (6 % 7) = 6
0 + (7 % 7) = 0
0 + (8 % 7) = 1
0 + (9 % 7) = 2
看看结果的分布,结果0到2出现两次,而3到6只出现一次。这种方法明显偏向于较小的值,通过扩展,大多数涉及该算法的情况都会有类似的行为。
现在让我们看看上面getRandomNumber()函数的结果,使用与上面相同的参数(rand()返回一个介于0和9(包括0和9)、min=0和max=6)之间的数字)在这种情况下,分数=1/(9+1)=0.1max-min+1仍然是7。
如果不用求模,而是用除法:
return min + (std::rand() % (max-min+1));
可能的结果:
0 + static_cast(7 * (0 * 0.1))) = 0 + static_cast(0) = 0
0 + static_cast(7 * (1 * 0.1))) = 0 + static_cast(0.7) = 0
0 + static_cast(7 * (2 * 0.1))) = 0 + static_cast(1.4) = 1
0 + static_cast(7 * (3 * 0.1))) = 0 + static_cast(2.1) = 2
0 + static_cast(7 * (4 * 0.1))) = 0 + static_cast(2.8) = 2
0 + static_cast(7 * (5 * 0.1))) = 0 + static_cast(3.5) = 3
0 + static_cast(7 * (6 * 0.1))) = 0 + static_cast(4.2) = 4
0 + static_cast(7 * (7 * 0.1))) = 0 + static_cast(4.9) = 4
0 + static_cast(7 * (8 * 0.1))) = 0 + static_cast(5.6) = 5
0 + static_cast(7 * (9 * 0.1))) = 0 + static_cast(6.3) = 6
这里的偏向仍然是稍微朝着较低的数字(0、2和4出现两次,而1、3、5和6出现一次),但它的分布要均匀得多。
尽管getRandomNumber()比模方法更难理解,但我们还是提倡使用division方法,因为它产生的结果偏差较小。
5 使用随机库
一个可能更好的解决方案是使用第三方库来为您处理所有这些内容。
-End-
本页共164段,5440个字符,7108 Byte(字节)